package sporteam.web.server;

import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Logger;

import javax.jdo.JDOException;
import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;

import org.json.JSONException;
import org.json.JSONObject;

import com.restfb.Connection;
import com.restfb.DefaultFacebookClient;
import com.restfb.FacebookClient;
import com.restfb.types.User;

import sporteam.common.PMF;
import sporteam.web.client.AEuser;
import sporteam.web.client.Activity;
import sporteam.web.client.Track;

public class UserLoadingUtils {
	private static final Logger MyLog = Logger.getLogger(UserLoadingUtils.class
			.getName());
	
	private static AEuser ae_user;

	// create backup user from a given user
	public static AEuser CreateBackupUser(AEuser user) {
		return new AEuser(user);
	}

	// loads tracks that need to be sent to the application
	// sends all tracks that are not synced with android
	public static ArrayList<Track> LoadTracks(AEuser user) {
		// tmp
		return user.GetTracks();
	}

	// loads tracks that need to be sent to the application
	// sends all tracks that are not synced with android
	public static ArrayList<Track> LoadTracks(AEuser user, long lastUpdatedTrack) {

		ArrayList<Track> tracks = user.GetTracks();
		ArrayList<Track> tracks_to_send = new ArrayList<Track>();

		MyLog.warning("looking for tracks..");

		// return all tracks if lastUpdated is 0
		if (lastUpdatedTrack == 0)
			return user.GetTracks();

		try {
			// iterate all tracks and check which ones are most recent then the
			// last updated track
			for (Track t : tracks) {
				if (t.getDate() > lastUpdatedTrack) {
					tracks_to_send.add(t);
					MyLog.warning("loaded track" + t.getName());
				}
			}
		} catch (Exception e) {
			MyLog.warning("error in loadTracks : " + e.toString());
		}

		return tracks_to_send;
	}

	public static void updateFriendList(String access_token) {
		// establish connection with facebook-graph API with a specific
		// access_token
		FacebookClient facebookClient = new DefaultFacebookClient(access_token);

		com.restfb.types.User facebook_user = facebookClient.fetchObject("me",
				com.restfb.types.User.class); // me - the facebook user logged
												// in ATM.
		Connection<com.restfb.types.User> myFriends = facebookClient
				.fetchConnection("me/friends", com.restfb.types.User.class);
		PersistenceManager pm = PMF.get().getPersistenceManager();

		// make default in activity to be false
		String InActivityStr = "not_in_act";

		for (com.restfb.types.User friend : myFriends.getData()) {
			try {
				AEuser friend_user = pm.getObjectById(AEuser.class, friend.getId());

				// add friend to my friends_list
				ae_user.addSporteamFriend(friend.getId() + ";" + friend.getName()
						+ ";" + InActivityStr + ";");

				// add myself too each friend's friend_list as well
				friend_user.addSporteamFriend(facebook_user.getId() + ";"
						+ facebook_user.getName() + ";" + InActivityStr + ";");

				friend_user.UpdateDate();
				pm.makePersistent(friend_user);
				MyLog.warning("added sporteam friend: " + friend.getId()
						+ "in act status: " + InActivityStr);
			}
			catch(JDOObjectNotFoundException e){
				//MyLog.warning(e.toString());
			}
			catch (Exception e) {
				MyLog.warning(e.toString());
			}
		}
		pm.makePersistent(ae_user);
		MyLog.warning("after updating u "
				+ ae_user.getSporteamFriends().size());
		
		pm.close();
	}

	// loads activities that need to be sent to the application
	// sends all activities that are not synced with android
	public static ArrayList<Activity> LoadActivities(AEuser user) {
		ArrayList<Activity> acts_to_send = null;
		ArrayList<Activity> current_activites = null;

		try {
			acts_to_send = new ArrayList<Activity>();
			current_activites = user.GetActivities();

			// filter activities
			for (Activity act : current_activites) {
				if (!act.isClosedActivity()) {
					acts_to_send.add(act);
				}
			}
		} catch (Exception e) {
			MyLog.warning(e.toString());
			return null;
		}

		return acts_to_send;
	}

	// loads user that need to be sent to the application
	// initializing irrelevant information
	public static AEuser LoadPartialUser(AEuser user) {
		AEuser backupUser = CreateBackupUser(user);
		backupUser.InitActivities();
		backupUser.InitTracks();
		backupUser.setFacebook_code("");
		backupUser.setReg_id("");
		return user;
	}

	// loads whole user from appengine as is
	public static AEuser LoadWholeUser(AEuser user) {
		return user;
	}

	// loads friends from user
	public static ArrayList<String> LoadFriends(AEuser user) {
		return user.getSporteamFriends();
	}

	public static void UpdateUserFriends(AEuser user, Activity act) {

		ArrayList<String> friends = user.getSporteamFriends();

		String friendID, friendName, InActivityStr;
		String updatedFriendStr = null;

		MyLog.warning("updating user friends..");

		try {
			for (String friendStr : friends) {
				// retrieve faceook ID
				friendID = GetInfoFromStr(friendStr, 0);

				// retrieve name
				friendName = GetInfoFromStr(friendStr, 1);

				if (act.getSenderID().equals(friendID)) {
					if (act.getReceiverTrack() != null) {
						InActivityStr = "not_in_act";
					} else
						InActivityStr = "in_act";

					updatedFriendStr = BuildFriendStr(friendID, friendName,
							InActivityStr);
					friends.remove(friendStr);
					friends.add(updatedFriendStr);

					MyLog.warning("updated" + user.GetFirstName()
							+ "activity status" + InActivityStr);

					break;
				} else if (act.getReceiverID().equals(friendID)) {
					if (act.isClosedActivity()) {
						InActivityStr = "not_in_act";
					} else
						InActivityStr = "in_act";

					updatedFriendStr = BuildFriendStr(friendID, friendName,
							InActivityStr);
					friends.remove(friendStr);
					friends.add(updatedFriendStr);
				}
			}
		} catch (Exception e) {
			MyLog.warning("error in UpdateUserFriends: " + e.toString());
		}

	}

	private static String GetInfoFromStr(String str, int index) {
		StringBuilder ret_str = new StringBuilder();
		int counter = 0;
		for (int i = 0; i < str.length(); i++) {
			if (str.charAt(i) == ';') {
				if (counter == index)
					break;
				else
					counter++;
			} else if (counter == index) {
				ret_str.append(str.charAt(i));
			}
		}

		return ret_str.toString();
	}

	private static String BuildFriendStr(String friendID, String friendName,
			String InActivityStr) {
		return friendID + ";" + friendName + ";" + InActivityStr + ";";
	}

	// handles new user registration
	// returns the user inserted to database
	public static AEuser HandleUserRegistration(String facebook_ID,
			String access_token) {
		if (access_token == null)
			access_token = "";
		try {
			if (access_token.equals("")) // in case no access token given
			{
				UserLoadingUtils.createFacebookUserAndStore(facebook_ID);
			} else {
				UserLoadingUtils.createFacebookUserAndStore(facebook_ID,
						access_token);
				UserLoadingUtils.updateFriendList(access_token);
			}

		} catch (Exception e) {
			MyLog.warning("Exception in handle user regsitration"
					+ e.toString());
		}
		return ae_user;
	}

	public static void createFacebookUserAndStore(String facebookID,
			String access_token) {
		// establish connection with facebook-graph API with a specific
		// access_token
		FacebookClient facebookClient = new DefaultFacebookClient(access_token);
		com.restfb.types.User facebook_user = facebookClient.fetchObject("me",
				com.restfb.types.User.class); // me - the facebook user logged
												// in ATM.

		ae_user = new AEuser();

		// Set the new user attributes.
		String[] name = facebook_user.getName().split(" ");
		String first_name = name[0].trim();
		String last_name = name[1].trim();
		ae_user.SetFacebookID(facebook_user.getId());
		// u.setFacebook_code(code);
		ae_user.SetFirstName(first_name);
		ae_user.SetLastName(last_name);
		ae_user.SetGender(facebook_user.getGender());
		ae_user.SetEmail(facebook_user.getEmail());
		ae_user.UpdateDate();
		ae_user.SetAge(ComputeAge(facebook_user.getBirthday()));

		// Store user
		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.makePersistent(ae_user);
		pm.close();
	}

	public static int ComputeAge(String birthday) {
		return 20; // tmp
	}

	public static void createFacebookUserAndStore(String facebookID) {
		ae_user = new AEuser();
		ae_user.SetFacebookID(facebookID);

		JSONObject userJson;
		try {
			userJson = JsonUtils.readJsonFromUrl("https://graph.facebook.com/"
					+ facebookID);
			ae_user.SetFirstName(userJson.getString("first_name"));
			ae_user.SetLastName(userJson.getString("last_name"));
			ae_user.SetGender(userJson.getString("gender"));

		} catch (Exception e) {
			ae_user.setAndroid_state("not_init");
		}

		// Store user
		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.makePersistent(ae_user);
		pm.close();
	}

}
